package ipc;


import ipc.Node;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import java.util.Vector;

import rddl.ActionGenerator;
import rddl.EvalException;
import rddl.RDDL;
import rddl.RDDL.LCONST;
import rddl.RDDL.PVARIABLE_DEF;
import rddl.RDDL.PVARIABLE_STATE_DEF;
import rddl.RDDL.PVAR_NAME;
import rddl.RDDL.PVAR_INST_DEF;
import rddl.parser.parser;

import java.util.Random;

public final class DotAgent<S extends State, A> extends Agent<S, A> {

	private myDD _valueDD;
	private Simulator<S,A> _sim;
	
    public DotAgent(String dotfile, String inst_name, Simulator<S, A> sim) throws Exception {
    	_valueDD = new dot2dd(dotfile).getDD();
    	
    	this.simulator_ = sim.copy();
    }

    @Override
    public A selectAction(S state, long timeout, int time) {
    	simulator_.setState(state);
    	simulator_.setTime(time);
    	
    	List<A> legals = simulator_.getLegalActions();
    	System.out.println(legals);
		
    	double maxQ = Double.NEGATIVE_INFINITY;
    	A maxA = null;
    	
    	for( A thisA : legals ){
    		double thisQ = computeQ(thisA, simulator_);
    		System.out.println(thisA + " " + thisQ);
    		if( thisQ > maxQ ){
    			maxQ = thisQ;
    			maxA = thisA;
    		}
    	}
    	
    	System.out.println(maxA);
    	
    	return maxA;
    }
	
    private double computeQ(A thisA, Simulator<S, A> simulator_) {
    	double avgQ = 0;
    	for( int i = 0 ; i < 10; ++i ){
    		Simulator<S, A> clone = simulator_.copy();
    		clone.takeAction(thisA);
    		try{
    			avgQ += (Double)(query(clone));
    		}catch(Exception e){}
    	}
    	return avgQ / 10;
    	
	}

    public double query(Simulator simulator) throws Exception{
    	
    	HashMap<String, Boolean> unwind  = new HashMap<String, Boolean>();
    	
    	IPCState thisstate = (IPCState)(simulator.getState());
    	
    	for (PVAR_NAME p : thisstate._alStateNames) {
    		
    		Object def_value = null;
			PVARIABLE_DEF pvar_def = thisstate._hmPVariables.get(p);
			if (!(pvar_def instanceof PVARIABLE_STATE_DEF) ||
				((PVARIABLE_STATE_DEF)pvar_def)._bNonFluent){
				System.err.println("Expected state variable, got nonfluent: " + p);
				System.exit(1);
			}
			def_value = ((PVARIABLE_STATE_DEF)pvar_def)._oDefValue;
			ArrayList<ArrayList<LCONST>> gfluents = null;
 
			try{
				gfluents = thisstate.generateAtoms(p);
			}catch(EvalException e){
				System.err.println("Could not ground " + p);
				System.exit(1);
			}

			for( ArrayList<LCONST> gfluent : gfluents ){
				Object val = (thisstate._state.get(p).get(gfluent));
				boolean value =  ((Boolean)( val == null ? def_value : val )).booleanValue();
				unwind.put(rddl.translate.RDDL2Format.CleanFluentName(p.toString()+gfluent), value);
			}
    	}
    
//    	System.out.println(unwind);

    	double val = 0;
		val = extractValue(_valueDD.walk(unwind));
    	
    	return val;
    }
    
    public static double extractValue(String s) throws Exception{
    	if( s == null ){
    		throw new RuntimeException("Empty fluent");
    	}
    	s = s.trim();
    	return Double.parseDouble((s.split("\\s+"))[1]);
    }
    
    public static void main(String[] args) throws Exception {
    	
    	Relay.init("localhost", 2316 );
    	
    	System.out.println("connected");
    	
    	Relay r = Relay.sessionInit("sysadmin_small");
    	
    	System.out.println(r.numRounds);
    	
    	System.out.println("loading rddl...");
    	
    	RDDL rddl = new RDDL();
    	rddl.addOtherRDDL(parser.parse(new File("/scratch/final_comp/rddl/sysadmin_mdp.rddl")));
    	rddl.addOtherRDDL(parser.parse(new File("/scratch/final_comp/rddl/sysadmin_small.rddl")));
    	
    	String dotfile = "./sysadmin_small_2.dot";
    	String inst_name = "sysadmin_small" ;
    	
    	System.out.println("making sim");
    	
    	Simulator<IPCState, IPCAction> sim = new IPCSimulator(rddl, inst_name, System.currentTimeMillis());
    	
		DotAgent<IPCState, IPCAction> dotplayer = new DotAgent<IPCState, IPCAction>(dotfile, inst_name, sim);
		
		List<Agent<IPCState, IPCAction>> agents = new ArrayList<Agent<IPCState, IPCAction>>();
		agents.add(dotplayer);
		
		Arbiter<IPCState, IPCAction> arb = new Arbiter<IPCState, IPCAction>(sim, agents);
		
		System.out.println("running sims");
		
		arb.runSimulations(sim, 30, 1, 1);
		
		System.out.println(arb.getMean() + " " + arb.getVariance());
		
	}
}
